/************************************************************************
This file is part of java core libraries for the simpleRTJ virtual machine.

This file is covered by the GNU GPL with the following exception:
  As a special exception, the copyright holders of this library give you permission
  to link this library with independent modules to produce an executable, regardless
  of the license terms of these independent modules, and to copy and distribute the
  resulting executable under terms of your choice, provided that you also meet, for
  each linked independent module, the terms and conditions of the license of that
  module. An independent module is a module which is not derived from or based on
  this library. If you modify this library, you may extend this exception to your
  version of the library, but you are not obligated to do so. If you do not wish
  to do so, delete this exception statement from your version.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL RTJ COMPUTING BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Copyright (c) 2000-2002 RTJ Computing Pty. Ltd. All rights reserved.
***********************************************************************/
package javax.events;

/**
 * Events dispatcher class. The run() method of this class implements an infinite loop
 * in which this thread waits (suspended) for an event to occur. When an event is
 * recognised the VM thread scheduler immediately resumes this thread so it can
 * call fire() methods of registered AsyncEvent handler.
 * <p>
 * Note: There can be only one instance of this thread. If there are more instances
 * of this class then only the last created instance will receive event notifications.
 * <p>
 * Events class assumes that the appropriate fire counters are implemented in native code.
 * The order of fire counters must match the order and type of AsyncEvent objects that were
 * added to the evList using the addEvent method.<br>
 * Note that Timer event handler must be always present at index zero.
 * <p>
 * If there are several events pending then they are processed in turn until all fire counters
 * are decremented to zero.
 */
public class Events extends Thread
{
    public static final int ALL_EVENTS  = -1;

    /**
     * Number of events is retrieved from the native code.
     */
    public static int MAX_EVENTS = getEventsCount();
    /**
     * An array of AsyncEvent objects that are recoginsed in the native code.
     */
    private static AsyncEvent evList[] = new AsyncEvent[MAX_EVENTS];

    /**
     * Thread execution method implementing infinite loop which execution is resumed on
     * every event recognition. Once all events are processed thread enters
     * a suspend mode.
     */
    public void run()
    {
        // make this daemon thread so it can be killed with the last non-daemon thread
        setDaemon(true);
        // register this thread with the VM thread scheduler
        eventThreadRegister();
        while (true)
        {
            int evId = getEvent();

            // no more events to process -- suspend this thread
            if (evId < 0)
            {
                suspend();
                continue;
            }
            if (evId < evList.length && evList[evId] != null)
                evList[evId].fire();
        }
    }

    /**
     * Adds a new event into the list of registerd events.<br>
     * Particular events must be placed at indexes in the evList that match the
     * order of fire counters implemented in native code.<br>
     * Note that the Timer event must be always at index zero.
     * @param event     a new event
     * @param pos       index to the evList
     * @return true if successful, false if specified position is invalid or there is
     *  an event already associated with this position.
     * @exception EventLimitException thrown when the event index is out of bounds
     */
    public void addEvent(AsyncEvent event, int index) throws EventLimitException
    {
        if (index >= 0 && index < evList.length)
        {
            evList[index] = event;
            return;
        }
        throw new EventLimitException();
    }

    /**
     * Removes all events from the list of registerd events.
     */
    public void removeAll()
    {
        for (int i=0; i < evList.length; i++)
            evList[i] = null;
    }

    /**
     * There is a counter associated with each event. It is possible that the counter
     * is incremented faster than corresponding event hadler can process requests.
     * This method will clear fire counter for the specified event.
     * @param event   async event for which fire counter should be cleared
     */
    public boolean clearPendingFireCount(AsyncEvent event)
    {
        for (int i=0; i < evList.length; i++)
        {
            if (evList[i] != null && evList[i] == event)
            {
                clearPendingFireCount(i);
                return true;
            }
        }
        return false;
    }

    /**
     * Register this thread with the VM's thread execution scheduler. When an event
     * is recognised the thread scheduler will instantly resume execution of this thread
     * so that appropriate fire() methods of AsyncEvent classes can be invoked.
     */
    private native void eventThreadRegister();

    /**
     * Get an ID of the next pending event.
     * @return  ID of the pending event if successful, otherwise -1 is returned.
     */
    private native int getEvent();

    /**
     * Accompanying method for clearPendingFireCount.
     * This method will clear fire counter for the event specified by its ID.
     * If ALL_EVENTS is specified then all fire counters are cleared.
     * @param eventId   event ID for which fire counter should be cleared.
     */
    public native void clearPendingFireCount(int eventId);

    /**
     * Native method returning the count of events for which JVM created
     * fire counters.
     * @return max. number of event handlers that can be registered
     */
    private static native int getEventsCount();
}


